import { nanoid } from "nanoid";

type FetchHttpMethod =
  | "GET"
  | "HEAD"
  | "PATCH"
  | "POST"
  | "PUT"
  | "DELETE"
  | "CONNECT"
  | "OPTIONS"
  | "TRACE"
  | "get"
  | "head"
  | "patch"
  | "post"
  | "put"
  | "delete"
  | "connect"
  | "options"
  | "trace";

const header = (url: string) => {
  const { token } = url.startsWith("/admin") ? useAdminAuth() : useAuth();
  const h: any = { "Content-Type": "application/json" };
  if (token && token.value) {
    h["Authorization"] = `Bearer ${token.value}`;
  }
  h["X-Path"] = url;
  return { ...h };
};

const body = (body?: any) => {
  if (body) {
    return JSON.stringify(body);
  }
  return body;
};

export default function use$fetch() {
  const baseURL = useRuntimeConfig().public.apiUrl;
  const { isLoading, toast } = useStatus();
  const { throwApiError, ifApiError } = useApiError();

  const _fetch = async <T>(
    url: string,
    options: {
      method?: FetchHttpMethod;
      body?: any;
      onSuccess?: (v: T | null) => T | null;
      query?: Record<string, any>;
    }
  ) => {
    isLoading.value = true;
    return useAsyncData(nanoid(), () =>
      $fetch<T>(url, {
        method: options.method,
        baseURL,
        body: body(options.body),
        headers: header(url),
        query: options.query,
      })
        .then((v) => {
          try {
            const resp = v as ApiResp<T>;
            if (resp.code !== 0) {
              throwApiError(resp.msg);
            }
            if (options.onSuccess) {
              return options.onSuccess(resp.data);
            }
            return resp.data;
          } catch (e) {
            console.log(e);
            throwApiError((e as Error).message);
          }
        })

        .catch((e) => {
          console.log("catch:", e);
          toast.value = ifApiError(e, "请检查网络");
        })
        .finally(() => {
          isLoading.value = false;
        })
    );
  };

  const $get = async <T>(
    url: string,
    onSuccess?: (v: T | null) => T | null,
    query?: Record<string, any>
  ) => await _fetch<T>(url, { method: "GET", onSuccess, query });

  const $post = async <T>(
    url: string,
    body?: any,
    onSuccess?: (v: T | null) => T | null
  ) => await _fetch<T>(url, { method: "POST", body, onSuccess });

  const $put = async <T>(
    url: string,
    body?: any,
    onSuccess?: (v: T | null) => T | null
  ) => await _fetch<T>(url, { method: "PUT", body, onSuccess });

  const $patch = async <T>(
    url: string,
    body?: any,
    onSuccess?: (v: T | null) => T | null
  ) => await _fetch<T>(url, { method: "PATCH", body, onSuccess });

  const $del = async <T>(url: string, onSuccess?: (v: T | null) => T | null) =>
    await _fetch<T>(url, { method: "DELETE", onSuccess });

  return { $get, $post, $put, $patch, $del };
}
